<template>
  <div
    class="vk-input"
    :class="{
      [`is-${size}`]: size,
      [`is-${type}`]: type,
      'is-disabled': disabled,
      'is-clearable': clearable,
      'is-prepend': $slots.prepend, // 前缀（说明和按钮）通过 $slots 可以拿到当前所有的 slot
      'is-append': $slots.append, // 后缀（说明和按钮）
      'is-prefix': $slots.prefix, // 前置（图标）
      'is-suffix': $slots.suffix, // 后置（图标）
      'is-focus': isFocus,
    }"
  >
    <!-- input -->
    <template v-if="type !== 'textarea'">
      <!-- prepend slot -->
      <div v-if="$slots.prepend" class="vk-input__prepend">
        <slot name="prepend"></slot>
      </div>
      <div class="vk-input__wrapper">
        <!-- prefix slot -->
        <span class="vk-input__prefix" v-if="$slots.prefix">
          <slot name="prefix"></slot>
        </span>
        <input
          ref="InputRef"
          v-bind="attrs"
          class="vk-input__inner"
          :class="{ 'is-disabled': disabled }"
          :disabled="disabled"
          :autocomplete="autocomplete"
          :placeholder="placeholder"
          :readonly="readonly"
          :autofocus="autofocus"
          :form="form"
          :type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
          v-model="innerValue"
          @input="handleInput"
          @focus="handleFocus"
          @blur="handleBlur"
          @change="handleChange"
        />
        <!-- suffix slot -->
        <span
          class="vk-input__suffix"
          v-if="$slots.suffix || showClear || showPasswordArea"
          @click="keepFocus"
        >
          <slot name="suffix"></slot>
          <Icon
            v-if="showClear"
            icon="circle-xmark"
            class="vk-input__clear"
            @click="clear"
            @mousedown.prevent="NOOP"
          ></Icon>
          <Icon
            v-if="showPasswordArea && !passwordVisible"
            icon="eye"
            class="vk-input__password"
            @click="togglePassword"
          ></Icon>
          <Icon
            v-if="showPasswordArea && passwordVisible"
            icon="eye-slash"
            class="vk-input__password"
            @click="togglePassword"
          ></Icon>
        </span>
      </div>
      <!-- append slot -->
      <div v-if="$slots.append" class="vk-input__append">
        <slot name="append"></slot>
      </div>
    </template>
    <!-- textarea -->
    <template v-else>
      <textarea
        ref="InputRef"
        v-bind="attrs"
        class="vk-textarea__wrapper"
        :class="{ 'is-disabled': disabled }"
        :disabled="disabled"
        :autocomplete="autocomplete"
        :placeholder="placeholder"
        :readonly="readonly"
        :autofocus="autofocus"
        :form="form"
        v-model="innerValue"
        @input="handleInput"
        @focus="handleFocus"
        @blur="handleBlur"
        @change="handleChange"
      ></textarea>
    </template>
  </div>
</template>

<script setup lang="ts">
import {
  defineProps,
  withDefaults,
  defineOptions,
  defineEmits,
  ref,
  watch,
  computed,
  useAttrs,
  Ref,
  nextTick,
  inject,
} from "vue";
import { InputProps, InputEmits } from "./types";
import Icon from "../Icon/Icon.vue";
import { formItemContextKey } from "../Form/types";
defineOptions({
  name: "VkInput",
  inheritAttrs: false, // 关闭继承属性的对应字段
});

const props = withDefaults(defineProps<InputProps>(), {
  type: "text",
  autocomplete: "off",
});
const emits = defineEmits<InputEmits>();
const attrs = useAttrs();
const innerValue = ref(props.modelValue);
const isFocus = ref(false);
const passwordVisible = ref(false);
const InputRef = ref() as Ref<HTMLInputElement>;
const FormItemContext = inject(formItemContextKey);
const runValidation = (trigger?: string) => {
  FormItemContext?.validate(trigger).catch((e) => {
    console.log(e.errors);
  });
};

const showClear = computed(() => {
  // !! 可以将其转换成一个 ' boolean '类型
  return (
    props.clearable && !props.disabled && !!innerValue.value && isFocus.value
  );
});

const showPasswordArea = computed(() => {
  return props.showPassword && !!innerValue.value && !props.disabled;
});

const togglePassword = () => {
  passwordVisible.value = !passwordVisible.value;
};

// 只是一个空函数,主要解决点击清空图标时，触发了blur事件的问题
const NOOP = () => {};

const keepFocus = async () => {
  await nextTick();
  InputRef.value.focus();
};

const clear = () => {
  console.log("clear");
  innerValue.value = "";
  emits("update:modelValue", "");
  emits("clear");
  emits("change", "");
  emits("input", "");
};

const handleInput = () => {
  // 使用 emits 方法将 innerValue 的值传递给父组件，更新父组件中绑定的 modelValue 属性。
  emits("update:modelValue", innerValue.value);
  emits("input", innerValue.value);
  runValidation("input");
};

const handleChange = () => {
  emits("change", innerValue.value);
  runValidation("change");
};
const handleFocus = (event: FocusEvent) => {
  isFocus.value = true;
  emits("focus", event);
};

const handleBlur = (event: FocusEvent) => {
  isFocus.value = false;
  emits("blur", event);
  runValidation("blur"); // 失焦时验证表单
};

watch(
  () => props.modelValue,
  (newValue) => {
    innerValue.value = newValue;
  }
);

defineExpose({
  ref: InputRef,
});
</script>

<style scoped></style>
